package com.atguyigu.codesday02;

import org.springframework.http.converter.json.GsonBuilderUtils;
import org.w3c.dom.ls.LSOutput;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
* 总结：  1 synchronized是java的内置关键字而ReentrantLock时java5以后的新发布的类
 *         2 synchronized一旦申请，如果获取不到锁会一直阻塞，这个阻塞的过程，用户无法控制
*
*    相似点：
这两种同步方式有很多相似之处，它们都是加锁方式同步，而且都是阻塞式的同步，也就是说当如果一个线程获得了对象锁，
* 进入了同步块，其他访问该同步块的线程都必须阻塞在同步块外面等待，
* 而进行线程阻塞和唤醒的代价是比较高的（操作系统需要在用户态与内核态之间来回切换，代价很高，
* 不过可以通过对锁优化进行改善）。

功能区别：
这两种方式最大区别就是对于Synchronized来说，它是java语言的关键字，是原生语法层面的互斥，需要jvm实现。
* 而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁，需要lock()和unlock()方法配合try/finally语句块来完成

便利性：很明显Synchronized的使用比较方便简洁，并且由编译器去保证锁的加锁和释放，
* 而ReenTrantLock需要手工声明来加锁和释放锁，为了避免忘记手工释放锁造成死锁，所以最好在finally中声明释放锁。

锁的细粒度和灵活度：很明显ReenTrantLock优于Synchronized

性能的区别：
在Synchronized优化以前，synchronized的性能是比ReenTrantLock差很多的，但是自从Synchronized引入了偏向锁，
* 轻量级锁（自旋锁）后，两者的性能就差不多了，在两种方法都可用的情况下，官方甚至建议使用synchronized，
* 其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决，避免进入内核态的线程阻塞。
* */




//资源类
class MyResource {
//   public synchronized void mi() {
//
//        System.out.println(Thread.currentThread().getName() + "/t" + "________come in");
//        try {
//            TimeUnit.SECONDS.sleep(3);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }


    Lock lock = new ReentrantLock();
    public void m2() throws InterruptedException {

        if (lock.tryLock(1, TimeUnit.SECONDS)) {

            try {
                System.out.println(Thread.currentThread().getName() + "\t" + "----come in");
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                lock.unlock();
            }


        } else {

            System.out.println(Thread.currentThread().getName() + "\t" + "===强锁失败");
        }

    }

}



public class SyncVsReentrantLockDemo {


    public static void main(String[] args) {

     MyResource myResource= new MyResource();

       new Thread(()-> {
           try {
               myResource.m2();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       },"t1").start();




        new Thread(()-> {
            try {
                myResource.m2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t2").start();
    }
}